package jalgebrava.group.groups;

import static jalgebrava.util.Pair.*;
import jalgebrava.group.Group;
import jalgebrava.util.Pair;
import jalgebrava.util.collections.ImmutableIterable;
import jalgebrava.util.collections.IterableUtil;


class DirectProductGroupFactory {
	
	@SuppressWarnings("unused") // just there to keep EMMA happy
	private final static DirectProductGroupFactory instance = new DirectProductGroupFactory();
	private DirectProductGroupFactory() {
		// empty
	}
	final static <G,H> Group<Pair<G,H>> mk(final Group<G> g, final Group<H> h) {
		// no caching (yet?)		
		ImmutableIterable<Pair<G,H>> it = directProductIterable(g, h);
		
		return new AbstractGroup<Pair<G,H>>(g.getDescription() + "x" + h.getDescription(), it, g.size() * h.size()) {

			@Override
			public Pair<G,H> unit() {
				return pair(g.unit(), h.unit());
			}

			@Override
			public Pair<G,H> inv(Pair<G,H> x) {
				return pair(g.inv(x.a), h.inv(x.b));
			}

			@Override
			public Pair<G,H> mul(Pair<G,H> x, Pair<G,H> y) {
				return pair(g.mul(x.a,y.a),h.mul(x.b,y.b));
			}

			
			@Override
			public String toShortString(Pair<G, H> gh) {
				return "(" + g.toShortString(gh.a) + "," + h.toShortString(gh.b) + ")";
			}
			
			@Override
			public String toString(Pair<G, H> x) {
				return "(" + g.toString(x.a) + "," + h.toString(x.b) + ")";
			}

			@Override
			public boolean contains(Pair<G, H> x) {
				return g.contains(x.a) && h.contains(x.b);
			}
			
			
		};
	}
	
	private final static <G,H> ImmutableIterable<Pair<G,H>> directProductIterable(final Group<G> g, final Group<H> h) {
		
		return IterableUtil.cartesianProduct(g, h);
		
	}
}
